<?php

namespace app\service;

use app\model\Factory;
use app\model\FactoryBuildMaterial;
use app\model\FactoryMaterial;
use app\model\Material;
use app\model\UserFactory;
use app\model\UserFactoryMaterial;
use app\model\UserFactorySeat;
use app\model\UserIngredient;
use app\model\UserMaterial;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;

class UserFactoryService extends BaseService
{


    /**
     * 获取所有工厂的状态
     */
    public function get_factory_status($user_id): array
    {
        $user_factory_list = (new UserFactory())->field('id,state,build_time,build_end_time')->where('user_id', $user_id)->select();
        return $this->returnSuccess($user_factory_list);
    }

    /**
     * 获取工厂队列状态
     * @throws ModelNotFoundException
     * @throws DataNotFoundException
     * @throws DbException
     */
    public function get_factory_queue_status($user_id, $user_factory_id): array
    {
        $user_factory = (new UserFactory())->with('queue')->field('id,state')->where('user_id', $user_id)->select();
        return $this->returnSuccess($user_factory);
    }


    /**
     * 工厂列表
     * @throws ModelNotFoundException
     * @throws DataNotFoundException
     * @throws DbException
     */
    public function list($user_id): array
    {
        $factory_list = (new Factory())->select();

        $user_factory_list = (new UserFactory())->where('user_id', $user_id)->select();


        //处理数据
        foreach ($factory_list as &$factory) {

            $factory->own_num = 0;
            foreach ($user_factory_list as $user_factory) {
                if ($user_factory->factory_id == $factory->id) {
                    $factory->own_num += 1;
                }
            }
            //需要的建造材料
            $factory_item = (new Material())->with('factoryBuildMaterial')->where('factory_id', $factory->id)->where('need_lv', 1)->find();


            $factory->need = [
                'time' => $factory_item->build_time,//需要的时间
                'coin' => $factory_item->need_coin,//需要的金币
                'build_material' => $factory_item->factoryBuildMaterial->toArray(),//需要的建造材料
            ];


            $this->handleModelData($factory);
        }


        return $this->returnSuccess($factory_list);

    }

    /**
     * 工厂详情
     */
    public function details($user_id, $user_factory_id): array
    {

        $user_factory = (new UserFactory())->with(['factory', 'material', 'seat'])->find($user_factory_id);

        if (!$user_factory) {
            return $this->returnFail('工厂不存在');
        }

        //最大槽位
        $max_seat_num = $user_factory->max_seat_num;
        //正在使用的槽位
        $use_seat_num = $user_factory->max_seat_num - $user_factory->seat_num;
        //工厂最大等级
        $max_lv = $user_factory->factory->max_lv;
        //工厂当前等级
        $lv = $user_factory->lv;
        //可生产工具列表
        $material_list = $user_factory->material;

        //用户的所有工厂材料
        $user_ingredients_list = (new UserIngredient())->field('ingredients_id,num')->where('user_id', $user_id)->select();
        //将数据转换成 ingredients_id做key  num做value
        $user_ingredients_list = array_column($user_ingredients_list->toArray(), 'num', 'ingredients_id');


        //获取其状态
        foreach ($material_list as &$material) {
            $factory_material = (new FactoryMaterial())->where('material_id', $material->id)->select();
            //处理数据
            foreach ($factory_material as &$item) {
                //已经拥有的数量
                $item->have_num = $user_ingredients_list[$item->need_ingredients_id] ?? 0;
                $this->handleModelData($item);
            }

            $this->handleModelData($material);

            //是否可以生产
            $material->is_unlock = 0;
            $material_ids = $user_factory->material_ids;
            $material_ids = explode(',', $material_ids);
            if (in_array($material->id, $material_ids)) {
                $material->is_unlock = 1;
            }

            $material->item = $factory_material;
        }

        $seat = $user_factory->seat;

        foreach ($seat as &$item) {
            $this->handleModelData($item);
        }


        $data = [
            'id' => $user_factory->id,//用户工厂id
            'state' => $user_factory->state,//是否装备 0已购买  1建造中 2完成
            'position' => $user_factory->position,//位置
            'max_seat_num' => $max_seat_num,//最大槽位
            'use_seat_num' => $use_seat_num,//正在使用的槽位
            'max_lv' => $max_lv,//工厂最大等级
            'lv' => $lv,//工厂当前等级
            'material_list' => $material_list,//可生产工具列表
            'seat' => $seat,//当前槽位
        ];

        return $this->returnSuccess($data);

    }


    /**
     * 购买工厂
     * @throws ModelNotFoundException
     * @throws DataNotFoundException
     * @throws DbException
     */
    public function buy_factory($user_id, $factory_id): array
    {

        //用户已拥有该类工厂数量
        $user_factory_count = (new UserFactory())->where('user_id', $user_id)->where('factory_id', $factory_id)->count();

        $factory = (new Factory())->find($factory_id);
        if (!$factory) {
            return $this->returnFail('基类数据不存在');
        }

        if ($user_factory_count >= $factory->max_num) {
            return $this->returnFail('该工厂已达到最大建造数量');
        }

        //扣除金币
        $res_user_money = (new UserService())->change_money($user_id, $factory->price, USER_CAPITAL_TYPE['金币'], USER_CAPITAL_STATUS['扣除']);
        if (!$res_user_money['code']) {
            return $res_user_money;
        }

        //获取所需时间
        $build_time = (new Material())->where('factory_id', $factory->id)->value('build_time');

        if (!$build_time) {
            return $this->returnFail('基类数据不存在');
        }


        //创建工厂
        $user_factory = new UserFactory();
        $user_factory->user_id = $user_id;
        $user_factory->factory_id = $factory_id;
        $user_factory->lv = INIT_FACTORY_LV;
        $user_factory->seat_num = INIT_FACTORY_SEAT;
        $user_factory->max_seat_num = INIT_FACTORY_SEAT;
        $user_factory->build_time = $build_time;//建造所需时间
        $user_factory->state = FACTORY_STATE['已购买'];
        $user_factory->save();

        //去除多余字段
        $user_factory = $this->handleModelData($user_factory);
        return $this->returnSuccess($user_factory->toArray());
    }


    /**
     * 建造工厂
     * @throws ModelNotFoundException
     * @throws DbException
     * @throws DataNotFoundException
     */
    public function building($user_id, $user_factory_id, $status, $position = null): array
    {

        $user_factory = (new UserFactory())->with(['factoryMaxNum', 'material'])->where('user_id', $user_id)->find($user_factory_id);
        if (!$user_factory) {
            return $this->returnFail('用户工厂不存在');
        }


        //判断工厂状态
        if ($user_factory->state == FACTORY_STATE['已完成']) {
            //工厂已达到最大等级
            if ($user_factory->lv == $user_factory->factory->max_lv) {
                return $this->returnFail('工厂已达到最大等级');
            }
        }

        switch ($status) {
            case FACTORY_BUILD_STATUS['建造']:

                if (!$position) {
                    return $this->returnFail('请选择位置');
                }


                //查询当前工厂数量

                $user_factory_num = (new UserFactory())->where('user_id', $user_id)->where('factory_id', $user_factory_id)->count();

                $max_factory_num = $user_factory->max_num;

                if ($user_factory_num >= $max_factory_num) {
                    return $this->returnFail('工厂数量已到达上限');
                }

                if ($user_factory->state == FACTORY_STATE['建造中']) {
                    return $this->returnFail('工厂状态错误-该工厂已经在建造中');
                }

                if ($user_factory->state == FACTORY_STATE['待收取']) {
                    return $this->returnFail('工厂状态错误-该工厂建造已完成-请先收取');
                }

                if ($user_factory->state == FACTORY_STATE['已完成']) {
                    return $this->returnFail('工厂状态错误-该工厂建造已完成');
                }

                if ($user_factory->lv != 1) {
                    return $this->returnFail('工厂状态错误-需要去升级');
                }

                $user_factory->position = $position;

                $material = $user_factory->material[0];

                //将material_id 添加到$material_ids中
                $material_ids[] = $material->id;

                //将数组$material_ids转化成字符串用,分隔
                $material_ids_str = implode(',', $material_ids);
                $user_factory->material_ids = $material_ids_str;
                break;
            case FACTORY_BUILD_STATUS['升级']:
                if ($user_factory->state != FACTORY_STATE['已完成']) {
                    return $this->returnFail('工厂状态错误-无法升级');
                }
                $material = $user_factory->material[$user_factory->lv];

                $material_ids = $user_factory->material_ids;
                //将字符串$material_ids转化成数组
                $material_ids = explode(',', $material_ids);

                //将material_id 添加到$material_ids中
                $material_ids[] = $material->id;

                //将数组$material_ids转化成字符串用,分隔
                $material_ids_str = implode(',', $material_ids);
                $user_factory->material_ids = $material_ids_str;

                $user_factory->lv = $user_factory->lv + 1;
                break;
            default:
                return $this->returnFail('状态错误');
        }

        //需要的时间
        $build_time = $material->build_time;

        //需要的材料
        $need_ingredients = (new FactoryBuildMaterial())->where('material_id', $material->id)->select();

        $need_ingredients_ids = [];
        $need_ingredients_num_map = [];
        foreach ($need_ingredients as $need_ingredient) {
            $need_ingredients_ids[] = $need_ingredient->need_ingredients_id;
            $need_ingredients_num_map[$need_ingredient->need_ingredients_id] = $need_ingredient->num;
        }

        $user_ingredients = (new UserIngredient())->where('user_id', $user_id)->whereIn('ingredients_id', $need_ingredients_ids)->select();

        foreach ($user_ingredients as $user_ingredient) {
            $need_num = $need_ingredients_num_map[$user_ingredient->ingredients_id];
            if ($need_num > $user_ingredient->num) {
                return $this->returnFail('材料不足');
            }
            $user_ingredient->num = $user_ingredient->num - $need_num;
            $user_ingredient->save();
        }

        $user_factory->build_time = $build_time;
        $user_factory->build_end_time = date('Y-m-d H:i:s', time() + $build_time);
        $user_factory->state = FACTORY_STATE['建造中'];
        $user_factory->save();

        //消耗一名工人
        $res_user_worker = (new UserService())->change_worker($user_id, FACTORY_WORKER['工作']);
        if (!$res_user_worker['code']) {
            return $res_user_worker;
        }

        //去除多余字段
        $user_factory = $this->handleModelData($user_factory);

        $data = [
            'id' => $user_factory->id,
            'build_time' => $user_factory->build_time,
            'build_end_time' => $user_factory->build_end_time,
            'state' => $user_factory->state,
        ];

        return $this->returnSuccess($data);
    }


    /**
     * 建造/升级完成
     * @throws DataNotFoundException
     * @throws ModelNotFoundException
     * @throws DbException
     */
    public function complete($user_id, $user_factory_id): array
    {
        $user_factory = (new UserFactory())->where('user_id', $user_id)->find($user_factory_id);
        if (!$user_factory) {
            return $this->returnFail('用户工厂不存在');
        }

        if ($user_factory->state === FACTORY_STATE['已完成']) {
            return $this->returnFail('建造已完成');
        }

        if ($user_factory->state !== FACTORY_STATE['待收取']) {
            return $this->returnFail('建造未完成');
        }
        if ($user_factory->build_time >= date('Y-m-d H:i:s')) {
            return $this->returnFail('建造中-' . $user_factory->build_time);
        }


        $user_factory->state = FACTORY_STATE['已完成'];
        $user_factory->build_time = null;
        $user_factory->save();

        //收取材料
        $material = (new  Material())->with('ingredients')->where('factory_id', $user_factory->factory_id)->where('need_lv', $user_factory->lv)->find();


        if (!$material) {
            return $this->returnFail('材料不存在');
        }

        //赠送
        $res_user_ingredient = $this->change_ingredient($user_id, $material, true);
        if (!$res_user_ingredient['code']) {
            return $res_user_ingredient;
        }


        //去除多余字段
        // $user_factory = $this->handleModelData($user_factory);
        return $this->returnSuccess();
    }


    //赠送材料
    public function change_ingredient($user_id, $material, $is_build = false): array
    {
        if (!$material->ingredients) {
            return $this->returnFail('材料不存在');
        }

        $ingredients_id = $material->ingredients->id;

        if ($is_build) $material->num = $material->num * FACTORY_BUILD_GIVE_MATERIAL;

        $user_ingredient = (new UserIngredient())->where('user_id', $user_id)->where('ingredients_id', $ingredients_id)->find();
        if (!$user_ingredient) {
            $user_ingredient = new UserIngredient();
            $user_ingredient->user_id = $user_id;
            $user_ingredient->ingredients_id = $ingredients_id;
            $user_ingredient->num = $material->num;
        } else {
            $user_ingredient->num = $user_ingredient->num + $material->num;
        }
        $user_ingredient->save();

        //去除多余字段
        $user_ingredient = $this->handleModelData($user_ingredient);
        return $this->returnSuccess($user_ingredient->toArray());
    }


    /**
     * 生产工具
     * @throws ModelNotFoundException
     * @throws DbException
     * @throws DataNotFoundException
     */
    public function production($user_id, $user_factory_id, $material_id): array
    {
        $user_factory = (new UserFactory())->with('factory')->where('user_id', $user_id)->find($user_factory_id);
        if (!$user_factory) {
            return $this->returnFail('用户工厂不存在');
        }

        if ($user_factory->state !== FACTORY_STATE['已完成']) {
            return $this->returnFail('建造未完成,不能进行生产');
        }

        $material = (new Material())->find($material_id);

        if (!$material) {
            return $this->returnFail('材料不存在');
        }


        if (!$user_factory->seat_num) {
            return $this->returnFail('槽位已满,不能进行生产');
        }

        if ($user_factory->seat_num > $user_factory->max_seat_num) {
            return $this->returnFail('槽位已满,不能进行生产');
        }


        $factory_material_list = (new FactoryMaterial())->where('material_id', $material_id)->select();


        foreach ($factory_material_list as $factory_material) {
            $user_ingredients = (new UserIngredient())->where('user_id', $user_id)->where('ingredients_id', $factory_material->need_ingredients_id)->find();

            if (!$user_ingredients) {
                return $this->returnFail('材料不足');
            }

            if ($user_ingredients->num < $factory_material->num) {
                return $this->returnFail('材料不足');
            }
            //扣除材料
            if ($user_ingredients->num == $factory_material->num) {//删除
                $user_ingredients->delete();
            } else {
                $user_ingredients->num = $user_ingredients->num - $factory_material->num;
                $user_ingredients->save();
            }
        }

        if ($user_factory->factory->need_money) {
            //扣除金币
            $res_user_money = (new UserService())->change_money($user_id, $user_factory->factory->need_money, USER_CAPITAL_TYPE['金币'], USER_CAPITAL_STATUS['扣除']);
            if (!$res_user_money['code']) {
                return $res_user_money;
            }
        }

        //添加到生产队列
        $user_factory_seat = new UserFactorySeat();
        $user_factory_seat->user_id = $user_id;
        $user_factory_seat->user_factory_id = $user_factory_id;
        $user_factory_seat->material_id = $material_id;
        $user_factory_seat->need_time = $material->need_time;

        //判断当前队列中是否有生产中的材料
        if ($user_factory->seat_num == $user_factory->max_seat_num) {
            $user_factory_seat->status = FACTORY_PRODUCTION['生产中'];
            $user_factory_seat->end_time = date('Y-m-d H:i:s', time() + $material->need_time);
        } else {
            $user_factory_seat->status = FACTORY_PRODUCTION['队列中'];
        }

        $user_factory->seat_num = $user_factory->seat_num - 1;
        $user_factory->save();

        $user_factory_seat->save();
        return $this->returnSuccess($user_factory_seat->toArray());
    }


    /**
     * 生产完成-获取成果
     * @throws DataNotFoundException
     * @throws ModelNotFoundException
     * @throws DbException
     */
    public function pick($user_id, $user_factory_id): array
    {
        $user_factory = (new UserFactory())->where('user_id', $user_id)->find($user_factory_id);
        if (!$user_factory) {
            return $this->returnFail('用户工厂不存在');
        }
        $user_factory_seat_list = (new UserFactorySeat())->where('user_id', $user_id)->where('user_factory_id', $user_factory_id)->where('status', FACTORY_PRODUCTION['待收取'])->select();


        $data_list = [];

        foreach ($user_factory_seat_list as $user_factory_seat) {
            //获取材料
            $material = (new Material())->with('ingredients')->find($user_factory_seat->material_id);
            if (!$material) {
                return $this->returnFail('材料不存在');
            }


            $user_factory_seat->status = FACTORY_PRODUCTION['已完成'];
            $user_factory_seat->save();

            //添加材料
            $res_user_ingredient = $this->change_ingredient($user_id, $material);
            if (!$res_user_ingredient['code']) {
                return $res_user_ingredient;
            }

            //空余槽位+1
            $user_factory->seat_num = $user_factory->seat_num + 1;
            $user_factory->save();

            $data_list[] = $user_factory_seat->toArray();
        }

        if ($data_list) {
            //去除多余字段
            return $this->returnSuccess($data_list);
        } else {
            return $this->returnFail('没有可领取的材料');
        }


    }

    /**
     * 修改工厂位置
     * @throws ModelNotFoundException
     * @throws DataNotFoundException
     * @throws DbException
     */
    public function change_position($user_id, $user_factory_id, $position_id): array
    {
        if (!$position_id) {
            return $this->returnFail('请选择位置');
        }
        $user_factory = (new UserFactory())->where('user_id', $user_id)->find($user_factory_id);
        if (!$user_factory) {
            return $this->returnFail('用户工厂不存在');
        }
        $user_factory->position = $position_id;
        $user_factory->save();
        return $this->returnSuccess();
    }


}